package hunterxhunter.greedisland.data.map;

import hunterxhunter.greedisland.data.enums.Collision;
import hunterxhunter.greedisland.entities.sprite.BodyEntity;
import java.awt.Color;
import java.awt.Point;
import java.awt.Rectangle;
import framework.eea.gui.Graphics;
import hunterxhunter.greedisland.data.CipherSerializable;
import java.io.File;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import org.jbox2d.dynamics.World;

/**
 *
 * @author Markus Schr&ouml;der
 */
public class Map extends CipherSerializable {

    public static final int MAX_WIDTH = 512;
    public static final int MAX_HEIGHT = 512;
    
    private Tile[][] tiles;
    
    public Map() {
        tiles = new Tile[MAX_WIDTH][MAX_HEIGHT];
    }
    
    
    //TILE
    
    public Tile getTile(int x, int y) {
        return getTile(x, y, true);
    }
    
    public Tile getTile(int x, int y, boolean useDefaultIfNull) {
        if(x < 0 || x >= MAX_WIDTH || y < 0 || y >= MAX_HEIGHT || (useDefaultIfNull && tiles[x][y] == null)) {
            return Tile.getDefault();
        }
        //lazy alloc
        if(tiles[x][y] == null) {
            tiles[x][y] = new Tile();
        }
        return tiles[x][y];
    }
    
    
    public boolean passable(int x, int y) {
        if(x < 0 || x >= MAX_WIDTH || y < 0 || y >= MAX_HEIGHT || tiles[x][y] == null) {
            return true;
        } 
        return tiles[x][y].isPassable();
    }
    
    
    
    //RENDER
    
    public void render(int offsetX, int offsetY, int tileSizeW, int tileSizeH, LayerType[] layers, boolean showBorder, Graphics g) {
        //int numberOfTiles = 0;
        
        Tile tile;
        Rectangle dest;
        Rectangle border;
        for(int y = 0; y < MAX_HEIGHT; y++) {
            for(int x = 0; x < MAX_WIDTH; x++) {
                tile = getTile(x, y);
                dest = calculateRectangle(x, y, offsetX, offsetY, tileSizeW, tileSizeH);
                
                //outside of window
                if(!g.contains(dest))
                    continue;
                
                for(LayerType layer : layers) {
                    if(tile.hasLayerType(layer))
                        g.drawImage(tile.getImageRef(layer), dest, tile.getSrc(layer));
                }
                
                //numberOfTiles++;
                
                if(showBorder) {
                    border = new Rectangle(dest);
                    border.grow(-1, -1);
                    if(tile.isPassable())
                        g.setColor(Color.lightGray);
                    else
                        g.setColor(Color.red);
                    
                    switch(tile.getCollision()) {
                        case LD: g.drawLine(border.x, border.y, border.x + border.width, border.y + border.height); break;
                        case RD: g.drawLine(border.x + border.width, border.y, border.x, border.y + border.height); break;
                        case LU: g.drawLine(border.x, border.y + border.height, border.x + border.width, border.y); break;
                        case RU: g.drawLine(border.x, border.y, border.x + border.width, border.y + border.height); break;
                        case ALL: 
                        case NO:
                            g.drawRect(border); break;
                    }
                }
            }  
        }
        
        //System.out.println(numberOfTiles);
    }
    
    private Rectangle calculateRectangle(int x, int y, int offsetX, int offsetY, int tileSizeW, int tileSizeH) {
        return new Rectangle(offsetX + tileSizeW*x, offsetY + tileSizeH*y, tileSizeW, tileSizeH);
    }
    
    
    //J2DBOX UPDATE
    
    public void updateWorld(int offsetX, int offsetY, int tileSizeW, int tileSizeH, World world) {
        //clear world
        /*
        Body blist = world.getBodyList();
        Body b;
        while((b = blist.getNext()) != null) {
            world.destroyBody(b);
        }*/
        
        Tile tile;
        Rectangle dest;
        BodyEntity tileBodyEntity;
        for(int y = 0; y < MAX_HEIGHT; y++) {
            for(int x = 0; x < MAX_WIDTH; x++) {
                tile = getTile(x, y);
                dest = calculateRectangle(x, y, offsetX, offsetY, tileSizeW, tileSizeH);
                Point movedLocation = new Point(dest.x + tileSizeW/2, dest.y + tileSizeH/2);
                if(!tile.isPassable())
                    tileBodyEntity = new BodyEntity("Tile("+x+","+y+")", movedLocation, dest.getSize(), tile.getCollision(), world);
            }  
        }
    }

    
    
    //IO
    
    public static Map loadMap(File file) {
        Map map = new Map();
        map.load(file);
        return map;
    }
    
    @Override
    public String getPassphrase() {
        return "Greed Island is a big island!";
    }

    @Override
    public void write(ObjectOutputStream oos) throws IOException {
        oos.writeObject(tiles);
    }

    @Override
    public void read(ObjectInputStream ois) throws IOException, ClassNotFoundException {
        tiles = (Tile[][]) ois.readObject();
    }
    
}
